<?php

namespace app\service;

use app\admin\model\Config;
use app\model\User;
use app\model\UserBalanceLog;
use app\model\UserInvite;
use app\model\UserOauth;
use libs\Redis;
use thans\jwt\facade\JWTAuth;

class UserService
{
	/**
	 * 根据openid获取用户信息
	 *
	 * @param string $openid
	 * @param string $platform
	 * @return array|string[]
	 */
	public static function getUserInfo(string $openid, string $platform)
	{
		$time = time();
		//判断是否已经注册
		$user_info = UserOauth::field('id, user_id, openid')
			->with(['user' => function ($query) {
				$query->where('status', User::STATUS_YES);
			}])
			->where('openid', $openid)
			->where('platform', $platform)
			->find();
		if ($user_info) {
			$token_info = [
				'id'          => $user_info['user_id'],
				'nickname'    => $user_info['nickname'],
				'avatar'      => $user_info['avatar'],
				'token'       => $user_info['token'],
				'bind_status' => $user_info['bind_status'],
			];
			$token      = JWTAuth::builder($token_info);
			\app\model\User::update([
				'id'         => $user_info['user_id'],
				'login_time' => $time,
				'login_ip'   => request()->ip(1),
			]);
			unset($token_info['id']);
			return array_merge($token_info, ['auth_token' => $token, 'openid' => $openid]);
		}
		return [];
	}

	/**
	 * 保存用户信息
	 *
	 * @param string $openid
	 * @param string $unionid
	 * @param string $provider
	 * @param string $platform
	 * @param array  $token_data
	 * @param array  $login_data
	 * @return array|string[]
	 * @throws \Exception
	 */
	public static function saveUser(string $openid, string $unionid, string $provider, string $platform, array $token_data, array $login_data, int $invite_type, int $invite_user_id = 0, string $invite_token = '', int $agent_id = 0)
	{
		try {
			//用户最后的用户ID
//            $last_user_id = \app\model\User::where('id', '>', 0)->order('id', 'desc')->value('id');
//            if (empty($last_user_id)) {
//                $last_user_id = 1;
//            }
			$time       = time();
			$user_token = createUserToken();//用户数据
			$code       = genRandomString(8);
			$user       = [
				'parent_user_id' => $invite_user_id,
				'agent_id'       => $agent_id,
				'code'           => $code,
				'username'       => genRandomString(),
				'nickname'       => '用户' . genRandomNumber(),
				'invite_type'    => $invite_type,
				'level'          => 1,
				'avatar'         => 'w3/tuike/oline/uploads/head.png',
				'login_time'     => $time,
				'login_ip'       => request()->ip(1),
				'join_ip'        => request()->ip(1),
				'token'          => $user_token,
				'chat_count'     => 50,
				'status'         => 1,
				'year'           => date('Y', $time),
				'month'          => date('n', $time),
				'day'            => date('j', $time),
			];
			$res        = \app\model\User::create($user);//生成token数据
			// 生成用户的密钥
			$res->save(['user_secret' => self::createUserSecret($res->id, $user_token, $code)]);
			$token_info = [
				'id'          => $res->id,
				'nickname'    => $user['nickname'],
				'token'       => $user_token,
				'bind_status' => 0,
			];
			$token      = JWTAuth::builder($token_info);
			$oauth      = [
				'user_id'              => $res->id,
				'provider'             => $provider,
				'platform'             => $platform,
				'unionid'              => $unionid,
				'openid'               => $openid,
				'access_info'          => json_encode([
					'access' => $token_data,
					'login'  => $login_data,
				], JSON_UNESCAPED_UNICODE),
				'access_token_expires' => $token_data['expiresAt'] ?? 0,
			];


			//添加邀请记录
			if ($invite_token) {
				UserInvite::create([
					'token'   => $invite_token,
					'user_id' => $res->id,
				]);
				// 建立关系链
				(new User())->createRank($invite_user_id, $res);
				//邀请人新增邀请人数
				\app\model\User::where('id', $invite_user_id)->setInc('invite_count');
			} else {
				$rank = '|' . $res->id . '|';
				$res->save(['rank' => $rank]);
			}

//            // 注册奖励佣金 增加发放奖励条件，所以这块的逻辑要去掉
//            self::reward($invite_user_id, $res->id);

			UserOauth::create($oauth);
			return array_merge($token_info, [
				'openid'     => $openid,
				'auth_token' => $token,
			]);
		} catch (\Exception $e) {
			throw new \Exception('保存用户信息失败：' . $e->getMessage());
		}
	}

	public static function getJwtUserInfo()
	{
		$user_info = JWTAuth::auth();
		return [
			'id'       => intval((string)$user_info['id']),
			'nickname' => (string)$user_info['nickname'],
			'token'    => (string)$user_info['token'],
		];
	}

	/**
	 * 注册奖励佣金
	 *
	 * @param $invite_user_id
	 * @param $user_id
	 * @return void
	 */
	public static function reward($invite_user_id, $user_id)
	{
		// 查询邀请人是否发放分佣
		$inviteUserBalanceLog   = UserBalanceLog::where('user_id', $invite_user_id)
			->where('from_user_id', $user_id)
			->where('scene', UserBalanceLog::SCENE_INVITE)
			->find();
		$registerUserBalanceLog = UserBalanceLog::where('user_id', $user_id)
			->where('from_user_id', $user_id)
			->where('scene', UserBalanceLog::SCENE_REGISTER)
			->find();

		// 如果邀请人或用户已发放分佣，则不重复发放
		if ($inviteUserBalanceLog || $registerUserBalanceLog) {
			return;
		}

		$inviteRewardPrice   = self::getInviteRewardPrice($invite_user_id);
		$registerRewardPrice = self::getRegisterRewardPrice();

		$userModel = new User();
		// 拉新奖励
		if (!empty($invite_user_id) && $inviteRewardPrice > 0) {
			$userModel->setIncMoney($invite_user_id, $inviteRewardPrice * 100);
			$userModel->setIncTotal($invite_user_id, $inviteRewardPrice * 100);
			(new UserBalanceLog())->save([
				'user_id'        => $invite_user_id,
				'from_user_id'   => $user_id,
				'type'           => UserBalanceLog::TYPE_NEED_RECEIVE,
				'scene'          => UserBalanceLog::SCENE_INVITE,
				'money'          => $inviteRewardPrice,
				'status'         => UserBalanceLog::STATUS_COMPLETED,
				'order_id'       => buildOrderNo(),
				'account_status' => UserBalanceLog::ACCOUNT_STATUS_COMPLETED, // 拉新奖励进入账户余额
			]);
		}

		// 注册奖励
		if (!empty($user_id) && $registerRewardPrice > 0) {
			$userModel->setIncTotal($user_id, $registerRewardPrice * 100);
			(new UserBalanceLog())->save([
				'user_id'        => $user_id,
				'from_user_id'   => $user_id,
				'type'           => UserBalanceLog::TYPE_REAL_TIME,
				'scene'          => UserBalanceLog::SCENE_REGISTER,
				'money'          => $registerRewardPrice,
				'status'         => UserBalanceLog::STATUS_COMPLETED,
				'order_id'       => buildOrderNo(),
				'account_status' => UserBalanceLog::ACCOUNT_STATUS_WAIT, // 注册奖励实时发放
			]);
		}
	}

	/**
	 * 获取邀请奖励金额
	 *
	 * @return string|int
	 */
	public static function getInviteRewardPrice($inviteUserId)
	{
		$config = Config::where('group', '=', 'commission')->column('value', 'name');
		if (empty($config)) {
			return 0;
		}

		/**
		 * 邀请奖励衰减：24小时内，同一个邀请码 注册且领取了奖励的用户超过 3 人
		 * 则 实际奖励 = 基础奖励(固定奖励金额) * max[(1 - 衰弱系数 * 同一邀请人24小时内注册且领取了奖励的用户数 / 阀值), 0]
		 **/
		$startCount        = 3; // 超过3人，则重新计算奖励金额
		$beginTime         = strtotime('-1 day');
		$inviteRewardCount = UserBalanceLog::where('user_id', $inviteUserId)
			->where('scene', UserBalanceLog::SCENE_INVITE)
			->where('create_time', '>=', $beginTime)
			->count();

		if ($inviteRewardCount >= $startCount) {
			$inviteWeakRatio = $config['invite_weak_ratio']; // 衰弱系数
			$inviteMaxNumber = $config['invite_max_number']; // 阀值

			// 衰弱系数 * 同一邀请人24小时内注册用户数 / 阀值
			$weakNumber = $inviteWeakRatio * $inviteRewardCount / $inviteMaxNumber;
			// 返回最终计算的奖励金额，最终结果，四舍五入
			return round($config['inviter'] * max(1 - $weakNumber, 0), 2);
		}

		return $config['inviter'];
	}

	/**
	 * 获取注册奖励金额
	 *
	 * @return string
	 */
	public static function getRegisterRewardPrice()
	{
		$price = Config::where('group', '=', 'commission')
			->where('name', 'register')
			->value('value');
		if (empty($price)) {
			return 0;
		}
		return $price;
	}


	/**
	 * 设置注册锁
	 *
	 * @param $openid
	 * @return bool
	 */
	public static function lockRegister($openid): bool
	{
		// 已设置返回false，未设置则设置锁
		$redisKey = sprintf(Redis::USER_REGISTER_LOCK, $openid);
		if (!Redis::getRedis()->setnx($redisKey, 1)) {
			return false;
		}
		return true;
	}

	/**
	 * 解除注册锁
	 *
	 * @param $openid
	 * @return bool
	 */
	public static function unlockRegister($openid): bool
	{
		$redisKey = sprintf(Redis::USER_REGISTER_LOCK, $openid);
		return Redis::getRedis()->del($redisKey);
	}

	/**
	 * 生成用户唯一密钥
	 *
	 * @param $userId
	 * @param $token
	 * @param $code
	 * @return string
	 */
	public static function createUserSecret($userId, $token, $code): string
	{
		$signStr = 'id=' . $userId . '&token=' . $token . '&code=' . $code;
		return md5($signStr);
	}
}
